package com.clj.SpringSecurityOAuth2Config.config;

import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;

import com.clj.SpringSecurityOAuth2Config.service.UserDetailService;

import ch.qos.logback.core.encoder.Encoder;
/**
 * AuthorizationServerConfigurerAdapter只是一个提供给开发配置ClientDetailsServiceConfigurer、AuthorizationServerEndpointsConfigurer、AuthorizationServerSecurityConfigurer空壳类并没有持有以上三个配置Bean对象。由初始化时调用AuthorizationServerConfigurerAdapter.configure(xxxConfigure) 给机会开发注入、配置。

开发定义的配置列表：

1. ClientDetailsService：ClientDetails信息加载实现类。

2. TokenStore：token管理服务。

3. TokenEnhancer：token信息的额外信息处理。

4. PasswordEncoder： clientDetail 信息里的client_secret字段加解密器。
 * @author C117
 * 
 * （1）ClientDetailsServiceConfigurer：clientDetailsService注入，决定clientDeatils信息的处理服务。
（2）AuthorizationServerEndpointsConfigurer：访问端点配置。tokenStroe、tokenEnhancer服务
（3）AuthorizationServerSecurityConfigurer：访问安全配置。
 *
 *
 *这里使用的AuthorizationServerConfigurerAdapter是Spring提供的默认实现AuthorizationServerConfigurer接口的类，里面都是空方法
 */
@Configuration  //同时@Configuration注解的实现了AuthorizationServerConfigurer接口的类表明这是一个authorization server配置类
@EnableAuthorizationServer  //使用@EnableAuthorizationServer注解告诉Spring激活authorization server
public class AuthorizationServerConfig  extends AuthorizationServerConfigurerAdapter {

	@Autowired
    private TokenStore jwtTokenStore;
    @Autowired
    private JwtAccessTokenConverter jwtAccessTokenConverter;
    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private TokenEnhancer tokenEnhancer;
    @Autowired
    private UserDetailService userDetailService;
	/**
	 * 一般项目中密码之类的字段都不会使用明文加密, 所以这里注入passwordEncoder，用于用户登录时密码校验以及创建用户时密码的加密
	 * @return
	 */
	@Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
	
	/**
	 * AuthorizationServerSecurityConfigurer：访问安全配置。
	 * 
	 */
	@Override
	public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
		// TODO Auto-generated method stub
		super.configure(security);
	}

	
	/**
	 * 主要是注入ClientDetailsService实例对象（唯一配置注入）。其它地方可以通过ClientDetailsServiceConfigurer调用开发配置的ClientDetailsService。系统提供的二个ClientDetailsService实现类：JdbcClientDetailsService、InMemoryClientDetailsService。
	 * 
	 * ClientDetailsServiceConfigurer是配置authorization server颁发的client的凭证  决定clientDeatils信息的处理服务




    client.inMemory()是在内存中存储client信息
    withClient和secret是client的username和password
    scopes是授权范围，例如该client可以进行读和写
    authorizedGrantTypes是配置授权方式, 可以是OAuth2.0中支持的方式，也可以是自定义的

	 */
	@Override
	public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
		clients.inMemory()
		.withClient("test1")
		.secret(new BCryptPasswordEncoder().encode("test1111"))
		.authorizedGrantTypes("password","refresh_token")
		.accessTokenValiditySeconds(3600)
		.refreshTokenValiditySeconds(864000)
		.scopes("all","a","b","c")
	.and()
		.withClient("test2")
		.secret(new BCryptPasswordEncoder().encode("test2222"))
		.accessTokenValiditySeconds(7200);
		
		
	}

	/**
	 * AuthorizationServerEndpointsConfigurer：访问端点配置。tokenStroe、tokenEnhancer服务
	 * 注入authenticationManager，这是Spring默认提供的，如果需要使用password模式，必须显示地配置endpoints.authenticationManager(authenticationManager)
	 * AuthorizationServerEndpointsConfigurer其实是一个装载类，装载Endpoints所有相关的类配置（AuthorizationServer、TokenServices、TokenStore、ClientDetailsService、UserDetailsService）。
	 * 	 * 注入相关配置：
	 * 1. 密码模式下配置认证管理器 AuthenticationManager
	 * 2. 设置 AccessToken的存储介质tokenStore， 默认使用内存当做存储介质。
      * 3. userDetailsService注入
	 */
	@Override
	public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
		TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
		List<TokenEnhancer> enhancers = new ArrayList<>();
		enhancers.add(tokenEnhancer);
		enhancers.add(jwtAccessTokenConverter);
		enhancerChain.setTokenEnhancers(enhancers);
		endpoints.authenticationManager(authenticationManager)
		.tokenStore(jwtTokenStore)
		.accessTokenConverter(jwtAccessTokenConverter)
		.userDetailsService(userDetailService); //密码模式下需设置一个AuthenticationManager对象,获取 UserDetails信息
		
	}

	
	
	
}
